package utils

import (
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"lin6xcom/src/models"
	"net/http"
	"time"
)

// 定义秘钥
var jwtkey = []byte("lin6x.com")

type FJwt struct{}

type Claims struct {
	UserId   uint   `json:"user_id"`
	Username string `json:"username"`
	jwt.StandardClaims
}

// CreateToken 创建用户令牌
// 参数:
//
//	user: 包含用户信息的模型，用于生成令牌中的用户标识和用户名
//
// 返回值:
//
//	生成的JWT令牌字符串
func (FJwt) CreateToken(user models.User) string {
	// 计算令牌的过期时间，从当前时间起7天后
	expireTime := time.Now().Add(7 * 24 * time.Hour)

	// 创建Claims结构体实例，填充用户ID、用户名以及标准声明信息
	claims := &Claims{
		UserId:   user.UserID,
		Username: user.Username,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: expireTime.Unix(), // 过期时间
			IssuedAt:  time.Now().Unix(),
			Issuer:    "lin6x.com", // 签名颁发者
			Subject:   "usertoken", // 签名主题
		},
	}

	// 使用HS256算法创建并填充自定义声明的JWT令牌
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// 使用密钥对令牌进行签名并转换为字符串形式
	tokenString, err := token.SignedString(jwtkey)
	if err != nil {
		fmt.Println(err)
	}

	// 返回生成的令牌字符串
	return tokenString
}

// Getting 是一个处理JWT令牌验证的函数。它是一个路由中间件
// 它通过 gin 框架的上下文对象获取请求的授权头信息，
// 并验证令牌的有效性。如果令牌有效，它会打印用户ID；
// 如果令牌无效或不存在，它会中止请求并返回权限不足的错误信息。
func (FJwt) Getting(ctx *gin.Context) {
	// 处理OPTIONS请求
	//if ctx.Request.Method == "OPTIONS" {
	//	ctx.Next()
	//	return
	//}
	// 从请求头中获取授权令牌。

	tokenString := ctx.GetHeader("Authorization")
	fmt.Println("进入处理", tokenString)
	// 检查令牌是否存在。如果不存在，返回权限不足的错误信息并中止请求。
	if tokenString == "" {
		ctx.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "权限不足"})
		ctx.Abort()
		return
	}

	// 解析并验证令牌。如果解析失败或令牌无效，返回权限不足的错误信息并中止请求。
	token, claims, err := ParseToken(tokenString)
	if err != nil || !token.Valid {
		ctx.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "权限不足"})
		ctx.Abort()
		return
	}

	// 打印调试信息，包括解析出的用户ID。
	fmt.Println(111)
	fmt.Println(claims.UserId)
}

// ParseToken 解析JWT令牌字符串，并返回令牌对象和自定义声明。
// 该函数使用jwt.ParseWithClaims方法解析给定的令牌字符串，并验证其签名。
// 参数:
//
//	tokenString (string): 待解析的JWT令牌字符串。
//
// 返回值:
//
//	*jwt.Token: 解析后的JWT令牌对象。
//	*Claims: 解析出的自定义声明对象。
//	error: 如果解析过程中发生错误，返回该错误。
func ParseToken(tokenString string) (*jwt.Token, *Claims, error) {
	// 创建一个空的Claims对象，用于存储解析后的声明数据。
	Claims := &Claims{}

	// 使用jwt.ParseWithClaims方法解析令牌字符串。
	// 第一个参数是待解析的令牌字符串。
	// 第二个参数是用于存储解析后声明的Claims对象。
	// 第三个参数是一个密钥函数，用于提供验证令牌签名所需的密钥。
	token, err := jwt.ParseWithClaims(tokenString, Claims, func(token *jwt.Token) (i interface{}, err error) {
		// 这里返回用于验证令牌签名的密钥。
		// 在实际应用中，这个密钥应该是安全存储并且保密的。
		return jwtkey, nil
	})

	// 将解析后的令牌对象、声明对象和可能的错误返回给调用者。
	return token, Claims, err
}
